package com.tyjw;

import java.util.Base64;
import java.util.concurrent.TimeUnit;

import com.tyjw.common.ToolUtil;
import com.tyjw.common.protos.TyjwDataPB;
import com.tyjw.common.protos.TyjwDataPB.SignalInfo;
import com.tyjw.common.protos.TyjwDataPB.TelemetryData;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class EapiTcpClientDemo{

	private final static String DOMAIN="http://api.wogrid.com";
	private final static String accessKeyID="";//TODO 替换为实际值
	private final static String accessKeySecret="";//TODO 替换为实际值
	private static String inetHost="api.wogrid.com";
	private static int inetPort=13002;
	
	
	private EventLoopGroup group = new NioEventLoopGroup();
    private Bootstrap bootstrap;
    private static Channel channel;

    
	public static void main(String[] args) throws Exception {
		new EapiTcpClientDemo().startClient();
	}
	
	
	public void startClient() {
		bootstrap = new Bootstrap();
		bootstrap.group(group)
    	.channel(NioSocketChannel.class)
        .option(ChannelOption.TCP_NODELAY, true)
        .option(ChannelOption.SO_SNDBUF, 1024*1024)
        .option(ChannelOption.SO_RCVBUF, 1024*1024)
        .handler(new ChannelInitializer<SocketChannel>() {
            public void initChannel(SocketChannel ch) throws Exception {
            	ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(10240,2,2,0,0));
            	ch.pipeline().addLast("ping", new IdleStateHandler(0, 3, 0, TimeUnit.SECONDS));
                ch.pipeline().addLast("simple",new SimpleChannelInboundHandler<ByteBuf>(){
                	@Override
                	public void channelRead0(ChannelHandlerContext ctx, ByteBuf byteBuf) throws Exception {
                		receiveData(byteBuf);
                	}
                    @Override
                    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
                    	channel=null;
                    	doConnect();
                    }
                    @Override
                    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
                        cause.printStackTrace();
                        ctx.close();
                     }
                    
                    @Override
                    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
                        if (evt instanceof IdleStateEvent) {//发送心跳
                    		ByteBuf buf=Unpooled.buffer();
                    		buf.writeShort(0x7479);
                    		buf.writeShort(0x09);
                    		buf.writeByte(0x02);
                    		buf.writeLong(System.currentTimeMillis());
                        	channel.writeAndFlush(buf);
                        }
                    }
                });  
            }  
        });
        doConnect();
	}
	
	
	
    protected void doConnect() {
        if (channel != null && channel.isActive()) {
            return;
        }
        ChannelFuture future = bootstrap.connect(inetHost, inetPort);
        log.info("开始连接平台");
        ToolUtil.getAccessToken(DOMAIN,accessKeyID,accessKeySecret);
        log.info("token:{}",ToolUtil.accessToken);
        future.addListener(new ChannelFutureListener() {
            public void operationComplete(ChannelFuture futureListener) throws Exception {
                if (futureListener.isSuccess()) {//TCP连接成功后，发注册请求
                    channel = futureListener.channel();
               		ByteBuf buf=Unpooled.buffer();
            		buf.writeShort(0x7479);
            		buf.writeShort(ToolUtil.accessToken.getBytes().length+5);
            		buf.writeByte(0x01);
            		buf.writeInt(ToolUtil.companyId);
            		buf.writeBytes(ToolUtil.accessToken.getBytes());
                	channel.writeAndFlush(buf);
                } else {
                    futureListener.channel().eventLoop().schedule(new Runnable() {
                        @Override
                        public void run() {
                        	log.info("重新连接平台");
                            doConnect();
                        }
                    }, 3, TimeUnit.SECONDS);
                }
            }
        });
    }
    
    
    //收到平台的数据
    private void receiveData(ByteBuf byteBuf) {
    	try {
//    		byte[] dd=new byte[byteBuf.readableBytes()];
//    		byteBuf.getBytes(0, dd);
//    		System.out.println(ByteUtil.bytes2HexString(dd));
    		if(byteBuf.getShort(0)==0x6A77){
    			switch (byteBuf.getByte(4)) {//指令编码
    				case 0x01://注册回复
    					break;
    				case (byte)0x0A://开关机通知
    					int state=byteBuf.getByte(5);
    					byte[] boxSn=new byte[15];
						byteBuf.skipBytes(6);
						byteBuf.readBytes(boxSn);
				    	log.info("{}{}",new String(boxSn),state==1?"开机":"关机");
    					break;
    				case (byte)0xD1://指令回复
    				    if(byteBuf.getByte(6)==0x23) {
    				    	byteBuf.skipBytes(12);
    				    	byte[] bs=new byte[15];
    				    	byteBuf.readBytes(bs);
    				    	log.info("收到云盒{}拍照回复",new String(bs));
    				    }
    					break;
    				case (byte)0x09://图片上传完成通知
    					byteBuf.skipBytes(38);
    				    byte[] box=new byte[15];
    				    byteBuf.readBytes(box);
    				    byte[] imgUrl=new byte[byteBuf.readableBytes()];
    				    byteBuf.readBytes(imgUrl);
    				    log.info("云盒{}图片上传成功,下载地址为:{}",new String(box),new String(imgUrl));
    					break;
    				case (byte)0xA9://下行遥测
    					byteBuf.skipBytes(5);
    				    byte[] A9=new byte[byteBuf.readableBytes()];
    				    byteBuf.readBytes(A9);
    				    TelemetryData telemetry=TelemetryData.parseFrom(A9);
    				    log.info(telemetry.toString());
    					break;
    				case (byte)0xA8://无人机状态
    					byteBuf.skipBytes(5);
					    byte[] A8=new byte[byteBuf.readableBytes()];
					    byteBuf.readBytes(A8);
					    TyjwDataPB.UavState uavState=TyjwDataPB.UavState.parseFrom(A8);
					    log.info(uavState.toString());
    					break;
    				case (byte)0x0C://信道质量
    					byteBuf.skipBytes(5);
    					byteBuf.readInt();//终端到平台的延时
    					byte[] sn=new byte[15];//云盒编号
     				    byteBuf.readBytes(sn);
    					byte[] signal=new byte[byteBuf.readableBytes()];
					    byteBuf.readBytes(signal);
					    SignalInfo singal=SignalInfo.parseFrom(signal);
					    log.info(singal.toString());
    					break;
    				default:
    					break;
    			}
    		}
    	}catch(Exception e) {
    		e.printStackTrace();
    	}
    }
    
    //发送数据到平台
    public  void sendData(byte[] data) {
    	channel.writeAndFlush(Unpooled.wrappedBuffer(data));
    }
    
    
    /**
     * 云台转动(基于速度)
     * @param boxSn 云盒编号
     * @param pitch 俯仰角
     * @param yaw 方向角
     * @param roll 横滚角
     */
    public void ptzController(String boxSn,float pitch,float yaw,float roll) {
    	ByteBuf buf=Unpooled.buffer();
		buf.writeShort(0x7479);//帧头
		buf.writeShort(0);//数据长度，占位临时赋值为0
		buf.writeBytes(boxSn.getBytes());//云盒编号
		buf.writeByte(0xD1);//指令编号
		buf.writeByte(0);//加密标志
		buf.writeByte(0xF4);//动作编号
		buf.writeFloat(pitch);//俯仰角
		buf.writeFloat(yaw);//方向角(平移)
		buf.writeFloat(roll);//横滚角
		buf.writeShort(200);//执行时间
		buf.setShort(2, buf.readableBytes()-4);//重新赋值数据长度
		byte[] data=new byte[buf.readableBytes()];
		buf.readBytes(data);
		sendData(data);
    }
    
    /**
     * 航线规划(通过TCP发给无人机)
     * @param boxSn 云盒编号
     * **/
    public void planLineToUav(String boxSn) {
		//规划航线
		TyjwDataPB.PlanLineData.Builder planLine=TyjwDataPB.PlanLineData.newBuilder();
		planLine.setFinishedAction(1);//结束航线后:返航
		planLine.setMaxSpeed(15);//最大飞行速度
		planLine.setAutoSpeed(15);//自动飞行速度
		planLine.setLoseAction(1);//网络失联后动作:继续航线
		planLine.setHomeHeight(100);//返航高度
		
		//航点
		TyjwDataPB.PointData.Builder point=TyjwDataPB.PointData.newBuilder();
		point.setLng(120.10127784287707);//航点经度
		point.setLat(31.43761516737881);//航点纬度
		point.setHeight(100);//航点高度
		point.setSpeed(15);//航点速度，如果不设置则使用自动飞行速度
		point.setFlightPathMode(1);//航线飞行模式:直线飞行
		//航线动作
		TyjwDataPB.PointAction.Builder action=TyjwDataPB.PointAction.newBuilder();
		action.setType(6);//控制云台俯仰
		action.setParam(-10);//设置俯仰角度
		point.setActions(0, action.build());
		//向航线中添加航点
		planLine.addPoints(point);
		
		byte[] lineData=planLine.build().toByteArray();
		
		//根据TCP协议格式组织发送的数据
    	ByteBuf buf=Unpooled.buffer();
		buf.writeShort(0x7479);//帧头
		buf.writeShort(0);//数据长度，占位临时赋值为0
		buf.writeBytes(boxSn.getBytes());//云盒编号
		buf.writeByte(0xD1);//指令编号
		buf.writeByte(0);//加密标志
		buf.writeByte(0x10);//动作编号
		buf.writeBytes(lineData);//航线数据
		buf.setShort(2, buf.readableBytes()-4);//重新赋值数据长度
		byte[] data=new byte[buf.readableBytes()];
		buf.readBytes(data);
		sendData(data);
    }
    
    /**
     * 规划机场航线(通过Http发给机场)
     * @param hangarId 机场编号
     * **/
    public void planLineTohangar(String hangarId) {
		//规划航线
		TyjwDataPB.PlanLineData.Builder planLine=TyjwDataPB.PlanLineData.newBuilder();
		planLine.setFinishedAction(1);//结束航线后:返航
		planLine.setMaxSpeed(15);//最大飞行速度
		planLine.setAutoSpeed(15);//自动飞行速度
		planLine.setLoseAction(1);//网络失联后动作:继续航线
		planLine.setHomeHeight(100);//返航高度
		//起降机库
		TyjwDataPB.HangarPoint.Builder hangarPoint=TyjwDataPB.HangarPoint.newBuilder();
		hangarPoint.setHangarId(hangarId);//机场编号
		hangarPoint.setHangarLng(120.11976472388368);//机场经度
		hangarPoint.setHangarLat(31.466260969370182);//机场纬度
		hangarPoint.setAlternateLng(120.10127784287707);//备降点经度
		hangarPoint.setAlternateLat(31.43761516737881);//备降点纬度
		planLine.setTakePoint(hangarPoint);//设置起飞机场
		planLine.setLandPoint(hangarPoint);//设置降落机场
		//航点
		TyjwDataPB.PointData.Builder point=TyjwDataPB.PointData.newBuilder();
		point.setLng(120.10127784287707);//航点经度
		point.setLat(31.43761516737881);//航点纬度
		point.setHeight(100);//航点高度
		point.setSpeed(15);//航点速度，如果不设置则使用自动飞行速度
		point.setFlightPathMode(1);//航线飞行模式:直线飞行
		//航线动作
		TyjwDataPB.PointAction.Builder action=TyjwDataPB.PointAction.newBuilder();
		action.setType(6);//控制云台俯仰
		action.setParam(-10);//设置俯仰角度
		point.setActions(0, action.build());
		//向航线中添加航点
		planLine.addPoints(point);
		
		byte[] lineData=planLine.build().toByteArray();
		String lineStr=Base64.getEncoder().encodeToString(lineData);
    	//TODO lineStr 为规划机场航线接口中lineData的值
    }
}
